home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Software Vault: The Gold Collection
/
Software Vault - The Gold Collection (American Databankers) (1993).ISO
/
cdr22
/
edconfig.zip
/
CONFIG.ASM
next >
Wrap
Assembly Source File
|
1993-05-25
|
42KB
|
978 lines
;----------------------------------------------------------------;
; CONFIG.CTL - Allows you to dynamically change your CONFIG.SYS ;
; configuration at boot time. Add DEVICE = CONFIG.CTL [m] ;
; to your CONFIG.SYS just ahead of the first command you wish ;
; to be able to modify. m is seconds CONFIG.CTL will pause ;
; for a keystroke before booting normally. m defaults to zero. ;
; Add DEVICE = CONFIG.END after the last command you wish to be ;
; able to modify. CONFIG.END is a dummy device and must appear ;
; in CONFIG.SYS in order for CONFIG.CTL to operate. ;
; ;
; CONFIG.CTL 1.0 (C) 1988 Ziff Communications Co.
;----------------------------------------------------------------;
_TEXT SEGMENT PUBLIC 'CODE' ;********************************;
ASSUME CS:_TEXT,DS:_TEXT ;* *;
ASSUME ES:_TEXT,SS:_TEXT ;* Requires MASM 2.0 or later *;
;* Remember to EXE2BIN *;
ORG 0H ;* *;
;********************************;
;COPYRIGHT DB "CONFIG.CTL 1.1 (c) 1988 Ziff Communications Co.",CR,LF
;PROGRAMMER DB "PC Magazine ",BOX," Michael J. Mefford",CR,LF,CTRL_Z
;************* DEVICE_HEADER *************;
POINTER DD -1
ATTRIBUTE DW 1000000000000000B
DEVICE_STAG DW STRATEGY
DEVICE_INT DW INTERRUPT
DEVICE_NAME DB "CONFIGURE"
CR EQU 13
LF EQU 10
CTRL_Z EQU 26
SPACE EQU 32
COMMA EQU 44
FORWARD_SLASH EQU 47
BOX EQU 254
;-------------------------;
REQUEST_HEADER STRUC
HEADER_LENGTH DB ?
UNIT_CODE DB ?
COMMAND_CODE DB ?
STATUS DW ?
RESERVED DQ ?
REQUEST_HEADER ENDS
DONE EQU 0000000100000000B ;Status codes.
UNKNOWN_CMD EQU 1000000000000011B
;-------------------------;
INIT STRUC
HEADER DB (TYPE REQUEST_HEADER) DUP(?)
UNITS DB ?
ENDING_OFFSET DW ?
ENDING_SEGMENT DW ?
ARGUMENTS_OFF DW ?
ARGUMENTS_SEG DW ?
INIT ENDS
REQUEST_OFFSET DW ?
REQUEST_SEG DW ?
; CODE AREA
; ---------
;-----------------------------------------------------------------------------;
; The only task of the strategy is to save the pointer to the request header. ;
;-----------------------------------------------------------------------------;
STRATEGY PROC FAR
MOV CS:REQUEST_OFFSET,BX ;Request header address is
MOV CS:REQUEST_SEG,ES ; passed in ES:BX.
RET
STRATEGY ENDP
;------------------------------------------------------------------------;
; The interrupt procedure will be called immediately after the strategy. ;
;------------------------------------------------------------------------;
INTERRUPT PROC FAR
PUSH AX ;Responsible for all registers.
PUSH BX
PUSH CX
PUSH DX
PUSH DS
PUSHF
MOV DS,CS:REQUEST_SEG ;Retrieve request header pointer.
MOV BX,CS:REQUEST_OFFSET
OR STATUS[BX],DONE ;Tell DOS we are done.
CMP COMMAND_CODE[BX],0 ;Is it INIT command?
JZ MAKE_STACK ;If yes, do our stuff.
OR STATUS[BX],UNKNOWN_CMD ;Else, exit with confused
JMP SHORT UNKNOWN_EXIT ; message to DOS.
MAKE_STACK: MOV CX,SS ;Save DOS stack.
MOV DX,SP
MOV AX,CS
CLI
MOV SS,AX ;Make new stack.
MOV SP,0FFFEH
STI
PUSH CX ;Save old stack pointers on new.
PUSH DX
PUSH ES ;Save rest of registers.
PUSH SI
PUSH DI
PUSH BP
CALL INITIALIZE ;Go do our stuff.
POP BP ;Restore registers.
POP DI
POP SI
POP ES
POP DX ;Restore old DOS stack.
POP CX
CLI
MOV SS,CX
MOV SP,DX
STI
UNKNOWN_EXIT: POPF ;Restore rest of registers.
POP DS
POP DX
POP CX
POP BX
POP AX
RET ;Far return back to DOS.
INTERRUPT ENDP
CONFIG_CTL_END LABEL WORD
;************* END OF RESIDENT PORTION *************;
BUFFER_SEGMENT DW ? ;CONFIG.SYS buffer segment
BUFFER_START DW ? ; and offset.
BUFFER_END DW ? ;CONFIG.END address.
END_FLAG DB 0 ;CONFIG.END found flag.
CONFIG_END DB "DCONFIG.END"
CONFIG_END_LEN EQU $ - CONFIG_END
DELAY_MSG DB CR,LF,LF,"Press any key if you wish to modify the "
DB "CONFIG.SYS configuration.",CR,LF
DB "Press Esc for quick bypass of CONFIG.CTL.",CR,LF,LF,"$"
NOT_FOUND_MSG DB "DEVICE = CONFIG.END has to be added as a terminating "
DB CR,LF
DB "command in CONFIG.SYS before CONFIG.CTL can function."
DB CR,LF
DB "Press and key to continue.$"
WRONG_VERSION DB "Requires DOS 2.x or greater.$"
;--------------------------;
NORMAL EQU 07H ;Screen attributes.
INVERSE EQU 70H
HEADING LABEL BYTE
DB "CONFIG.CTL 1.1 (c) 1988 Ziff Communications Co.",CR,LF
DB "PC Magazine ",BOX," Michael J. Mefford",CR,LF,LF
DB "Press F1 to toggle active state of highlighted command.",CR,LF
DB "You may optionally edit a highlighted command.",CR,LF
DB "Press F2 to accept changes and exit.",CR,LF
DB "Press Esc to abort changes and exit.",CR,LF
DB "Note: Permanent changes are not made to the CONFIG.SYS file.$"
;----------------------------;
STRING_MAX EQU 80
DISPLAY_MAX EQU 67
LAST_RECORD EQU -1
DATA_RECORD STRUC
COMMAND DB STRING_MAX DUP (?)
STRING_LENGTH DW ?
ADDRESS DW ? ;Command string address start.
DATA_RECORD ENDS
ROW_START EQU 9
COL_START EQU 12
CODES DB "CBQDXFSKL1I" ;DOS command codes.
CODES_LENGTH EQU $ - CODES ;For example "C" = BREAK
DOS_VERSION DB ?
DOS33 EQU 33
DOS4x EQU 4
COMMAND_TABLE DB "BREAK" ,5 DUP (SPACE), "BUFFERS" ,3 DUP (SPACE)
DB "COUNTRY" ,3 DUP (SPACE), "DEVICE" ,4 DUP (SPACE)
DB "FCBS" ,6 DUP (SPACE), "FILES" ,5 DUP (SPACE)
DB "SHELL" ,5 DUP (SPACE), "STACKS" ,4 DUP (SPACE)
DB "LASTDRIVE" ,1 DUP (SPACE), "SWITCHES",2 DUP (SPACE)
LAST_COMMAND DB "INSTALL" ,3 DUP (SPACE)
TABLE_END EQU $
COMMAND_SIZE EQU TABLE_END - LAST_COMMAND
INACTIVE DB "INACTIVE" ,2 DUP (SPACE)
HIGH_BIT EQU 10000000B
ESC_KEY EQU 01H
ENTER_KEY EQU 1CH
F1_KEY EQU 3BH
F2_KEY EQU 3CH
BACKSPACE_KEY EQU 0EH
UP_ARROW_KEY EQU 48H
DN_ARROW_KEY EQU 50H
LT_ARROW_KEY EQU 4BH
RT_ARROW_KEY EQU 4DH
HOME_KEY EQU 47H
END_KEY EQU 4FH
PG_UP_KEY EQU 49H
PG_DN_KEY EQU 51H
BS EQU 8
DISPATCH_KEY DB F1_KEY, BACKSPACE_KEY, UP_ARROW_KEY, DN_ARROW_KEY
DB LT_ARROW_KEY, RT_ARROW_KEY, HOME_KEY, END_KEY
DB PG_UP_KEY, PG_DN_KEY, ENTER_KEY
KEY_COUNT EQU $ - DISPATCH_KEY
DISPATCH_TABLE DW F1, BACKSPACE, UP_ARROW, DN_ARROW
DW LT_ARROW, RT_ARROW, HOME, END_CURSOR
DW PG_UP, PG_DN, DN_ARROW
DISPATCH_END EQU $ - 2
; ***************
; * SUBROUTINES *
; ***************
;------------------------------------------;
; INPUT ;
; DS:BX points to request header. ;
; ;
; All registers destroyed. ;
;------------------------------------------;
INITIALIZE PROC NEAR
MOV ENDING_OFFSET[BX],OFFSET CONFIG_CTL_END
MOV ENDING_SEGMENT[BX],CS ;Resident portion setup.
MOV AX,ARGUMENTS_SEG[BX] ;Retrieve CONFIG.SYS buffer
MOV ES,AX ; pointers from INIT table.
MOV BX,ARGUMENTS_OFF[BX]
PUSH CS ;Point to our data.
POP DS
MOV BUFFER_SEGMENT,ES ;And save the segment.
CLD
PUSH BX ;Save CONFIG.SYS buffer pointer.
MOV AH,30H ;Get DOS version.
INT 21H
POP BX ;Retrieve pointer.
OR AL,AL ;Is it DOS 2.x or greater?
JNZ CK_DOS3 ;If yes, continue.
MOV DX,OFFSET WRONG_VERSION ;Else, unsupported.
CALL PRINT_STRING
JMP INIT_END ;Exit.
CK_DOS3: CMP AL,3 ;Is it DOS 3.x?
JNZ CK_DOS4 ;If no, check DOS 4.
CMP AH,30 ;Is it DOS 3.30?
JB PARSE ;If no, done here.
MOV DOS_VERSION,DOS33 ;Else, take note.
CK_DOS4: CMP AL,4 ;Is it DOS 4.x?
JB PARSE ;If no, done here.
MOV DOS_VERSION,DOS4x ;Else, take note.
;------------------------------------;
; Parse CONFIG.CTL second parameter. ;
;------------------------------------;
PARSE: XOR BP,BP ;Use BP to store seconds.
NEXT_NUMBER: MOV AL,ES:[BX] ;Retrieve a byte.
INC BX ;Point to next byte.
CMP AL,CR ;If carriage return of linefeed,
JZ FIND_END ; found end of parameter.
CMP AL,LF
JZ FIND_END
SUB AL,"0" ;ASCII to binary.
JC NEXT_NUMBER ;If not between 0 and 9, skip.
CMP AL,9
JA NEXT_NUMBER
CBW ;Convert to word.
XCHG AX,BP ;Swap old and new number.
MOV CX,10 ;Shift to left by multiplying
MUL CX ; last entry by ten.
ADD BP,AX ;Add new number and store in BP.
JMP SHORT NEXT_NUMBER
;-----------------------------------------------------------------------;
; Search for dummy CONFIG.END device as signature of end of buffer. ;
; If found, replace "D" device code with "Z" unrecognized command code. ;
;-----------------------------------------------------------------------;
FIND_END: MOV BUFFER_START,BX ;Save start of first command.
NEXT_BYTE: MOV SI,OFFSET CONFIG_END ;Point to CONFIG.END.
MOV DI,BX ;Point to current buffer pos.
MOV CX,CONFIG_END_LEN ;Is it CONFIG.END?
REPZ CMPSB
JZ FOUND_END ;If yes, found end.
INC BX ;Else, increment buff pos.
CMP BX,0FFFFH - CONFIG_END_LEN ;End of segment?
JNZ NEXT_BYTE ;If no, continue.
JMP SHORT PAUSE ;Else, give up search.
FOUND_END: MOV END_FLAG,1 ;Flag that we found CONFIG.END.
MOV BYTE PTR ES:[BX],"Z" ;"Z" out CONFIG.END command.
DEC BX ;Adjust to buffer end
MOV BUFFER_END,BX ; and store.
;-------------------------------------------------------------;
; See if user pressed key requesting CONFIG.SYS modification. ;
;-------------------------------------------------------------;
PAUSE: CALL CK_KEY ;Key pressed?
JNZ ATTENTION ;If yes, give attention.
MOV CX,BP ;Else, retrieve second delay.
JCXZ INIT_END ;If zero, we're done.
MOV DX,OFFSET DELAY_MSG ;Else, display "Press key for
CALL PRINT_STRING ; service" message.
WAIT_A_SEC: CALL DELAY ;Delay a second.
POLL_KEY: CALL CK_KEY ;Key pressed?
JNZ ATTENTION ;If yes, give attention.
LOOP WAIT_A_SEC ;Else, continue waiting until
JMP SHORT INIT_END ; time out.
;--------------------------------------------------------------;
; If keystroke other than ESC was pressed and CONFIG.END dummy ;
; device found, then we're in business; otherwise exit.
;--------------------------------------------------------------;
ATTENTION: CALL GET_KEY ;Get the keystroke.
CMP AH,ESC_KEY ;Was is Esc?
JZ INIT_END ;If yes, we're done.
CMP END_FLAG,1 ;Else, did we find CONFIG.END?
JZ CONTINUE ;If yes, continue.
MOV DX,OFFSET NOT_FOUND_MSG ;Else, Display CONFIG.END not
CALL PRINT_STRING ; found message.
CALL GET_KEY ;Wait for keystroke so it can be
JMP SHORT INIT_END ; read and then exit.
CONTINUE: CALL BUSINESS ;Do our thing.
INIT_END: RET ;Exit.
INITIALIZE ENDP
;--------------------------------------------;
; INPUT ;
; DS = CS ;
; ES = CONFIG.SYS command buffer segment. ;
; ;
; All registers destroyed. ;
;--------------------------------------------;
BUSINESS PROC NEAR
CALL CLS ;Clear the screen.
MOV DX,OFFSET HEADING ;Display heading messages.
CALL PRINT_STRING
;----------------------------------------------------------------------------;
; Retrieve the commands from CONFIG.SYS buffer and place them in our buffer. ;
;----------------------------------------------------------------------------;
MOV SI,BUFFER_START ;Point to start of commands.
MOV DX,BUFFER_END ;DX = end of buffer.
MOV BX,OFFSET DATA_STORAGE ;Point to our storage.
PUSH CS ;Destination segment our data.
POP ES
PUSH BUFFER_SEGMENT ;Source segment CONFIG.SYS
POP DS ; command buffer.
NEXT_COMMAND: CMP SI,DX ;End of buffer?
JAE COMMAND_END ;If yes, done here.
LODSB ;Get a byte.
CMP AL,CR ;Carriage return or linefeed?
JZ NEXT_COMMAND ;If yes, delimiter; skip.
CMP AL,LF
JZ NEXT_COMMAND
PUSH AX ;Else, command code character.
DEC SI ;Adjust pointer.
MOV ES:ADDRESS[BX],SI ;Save starting address.
MOV DI,BX ;Point to our storage.
CALL RETRIEVE ;Go retrieve the command string.
POP AX ;Retrieve command code.
CMP AL,"Z" ;Was it unrecognized "Z" ?
JZ NEXT_COMMAND ;If yes, skip.
CMP AL,"0" ;Was it a DOS 4 REM?
JZ NEXT_COMMAND ;If yes, skip.
DEC CX ;Else, adjust string length.
JLE NEXT_COMMAND ;Null string? If yes, skip.
MOV ES:STRING_LENGTH[BX],CX ;Else, store length.
ADD BX,TYPE DATA_RECORD ;Point to next storage record.
JMP SHORT NEXT_COMMAND ;Get next command.
COMMAND_END: PUSH CS ;Back to our data segment.
POP DS
MOV COMMAND[BX],LAST_RECORD ; -1 as end of data signature.
CMP BX,OFFSET DATA_STORAGE ;Were there any commands?
JZ BUSINESS_END ;If no, done here.
;--------------------------------------------------;
; Display the commands and let the user edit them. ;
;--------------------------------------------------;
CALL DISPLAY_IT
CALL EDIT
JC BUSINESS_END ;If carry, Esc was pressed.
;----------------------------------------------------------;
; Place the edited commands back in the CONFIG.SYS buffer. ;
;----------------------------------------------------------;
MOV BX,OFFSET DATA_STORAGE ;Point to CONFIG.SYS buffer
PUSH BUFFER_SEGMENT ; as destination.
POP ES
STORE_COMMAND: CMP COMMAND[BX],LAST_RECORD ;Is it the last record?
JZ BUSINESS_END ;If yes, we're all done.
TEST COMMAND[BX],HIGH_BIT ;Is command inactive?
JZ REPLACE_DATA ;If no, OK.
MOV COMMAND[BX],"Z" ;Else, replace with "Z".
REPLACE_DATA: MOV SI,BX ;Point to command string.
MOV DI,ADDRESS[BX] ;Point to destination address.
CALL REPLACE ;Replace the string in buffer.
ADD BX,TYPE DATA_RECORD ;Point to next record.
JMP SHORT STORE_COMMAND ;And store it.
BUSINESS_END: CALL CLS ;Exit with clean slate.
RET
BUSINESS ENDP
;---------------------------------------;
; INPUT ;
; DS:SI points to CONFIG.SYS buffer. ;
; ES:DI points to our storage. ;
; ;
; OUTPUT ;
; SI and DI at end of string. ;
; CX = string length include one byte ;
; for CR or LF. ASCIIZ is stripped. ;
; ;
; AX destroyed. ;
;---------------------------------------;
RETRIEVE PROC NEAR
MOV CX,-1 ;Initialize counter.
LODSB ;Load and store code.
MOV AH,AL ;Preserve code.
STORE_IT: STOSB
INC CX
CMP AL,CR ;If terminating carriage return
JZ RETRIEVE_END ; or linefeed, we're done.
CMP AL,LF
JZ RETRIEVE_END
NEXT_RETRIEVE: LODSB ;Get a byte.
OR AL,AL ;Is it ASCIIZ zero?
JNZ STORE_IT ;If no, check CR or LF.
CMP BYTE PTR [SI],CR ;Else, end of parameters?
JBE NEXT_RETRIEVE ;If yes, skip.
CMP ES:DOS_VERSION,DOS33 ;Else, is it DOS 3.3?
JZ NEXT_RETRIEVE ;If yes, strip all zeros.
CMP AH,"S" ;Else, is it SHELL ASCIIZ?
JZ CONVERT ;If yes, convert to space.
CMP AH,"D" ;Else, is it a DEVICE ASCIIZ?
JZ CONVERT ;If yes, convert to space.
CMP AH,"I" ;Else, is it INSTALL?
JNZ NEXT_RETRIEVE ;If no, strip.
CONVERT: MOV AL,SPACE ;Else, convert to space.
JMP SHORT STORE_IT
RETRIEVE_END: RET
RETRIEVE ENDP
;--------------------------------------;
; INPUT ;
; DS:SI points to our storage. ;
; ES:DI points to CONFIG.SYS buffer. ;
; BX = current record. ;
; ;
; OUTPUT ;
; ASCIIZ is reinserted in string. ;
; SI and DI at end of string. ;
; ;
; AX, CX, DX, BP destroyed. ;
;--------------------------------------;
REPLACE PROC NEAR
MOV CX,STRING_LENGTH[BX] ;Retrieve string length.
INC CX ;Include command code byte.
MOV BP,-1 ;ASCIIZ flag.
XOR DX,DX ;Leading space flag.
MOV AH,[SI] ;Retrieve code.
NEXT_REPLACE: LODSB ;Get a byte.
CMP AL,"a" ;Capitalize.
JB CK_LEADING
CMP AL,"z"
JA CK_LEADING
AND AL,5FH
CK_LEADING: CMP AL,SPACE ;Is it a leading space?
JNZ CK_ADD_ZERO ;If no, check if zero time.
CMP DX,1 ;If command only thing stored
JZ NEXT_REPLACE ; so far, then it's leading.
CK_ADD_ZERO: CMP BP,-1 ;Have we stored a zero yet?
JNZ CK_CR_LF ;If yes, check CR and LF.
CMP AL,SPACE ;Else, is it space?
JZ CK_DOS ;If yes, check of DOS 4.
CMP AH,"Q" ;Is it COUNTRY?
JZ STORE_BYTE ;If yes, store the space.
CMP DOS_VERSION,DOS33 ;Else, is DOS 3.3?
JNZ STORE_BYTE ;If no, store the non space.
CMP AL,COMMA ;Else, is it a comma or slash?
JZ ASCIIZ ;If yes, ASCIIZ it.
CMP AL,FORWARD_SLASH
JZ ASCIIZ
JMP SHORT STORE_BYTE ;Else, just store the byte.
CK_DOS: CMP DOS_VERSION,DOS4x ;Is it DOS 4?
JNZ ASCIIZ ;If no, ASCIIZ.
CMP AH,"D" ;Else, is it DEVICE or SHELL?
JZ ASCIIZ ;If yes, ASCIIZ.
CMP AH,"S"
JZ ASCIIZ
CMP AH,"I" ;Or INSTALL of DOS 4.
JNZ STORE_BYTE ;Else, just store the byte.
ASCIIZ: XCHG AX,BP ;Swap special character.
XOR AX,AX ;Store the zero.
STOSB ;Retrieve the character and
XCHG AX,BP ; zero in BP as flag.
CMP DOS_VERSION,DOS33 ;Is it DOS 3.3?
JNZ BYTE_STORED ;If yes, store the char also.
CK_CR_LF: CMP AL,CR ;If CR or LF we're done here.
JZ PAD_SPACES
CMP AL,LF
JZ PAD_SPACES
STORE_BYTE: STOSB ;Store the byte.
BYTE_STORED: INC DX ;Increment count.
LOOP NEXT_REPLACE
PAD_SPACES: DEC CX ;Throw away CR or LF count.
JLE CK_ZERO ;If end of string, done.
MOV AL,SPACE ;Else, move leading spaces
REP STOSB ; to end of string.
CK_ZERO: CMP BP,-1 ;Have we replaced a zero yet?
JNZ REPLACE_END ;If yes done.
CMP DOS_VERSION,DOS4x ;Is it DOS 4.x?
JNZ ADD_ZERO ;If no, add a zero.
CMP AH,"S" ;Else, is it SHELL filename?
JZ ADD_ZERO ;If yes, ASCIIZ.
CMP AH,"D" ;Else, is it DEVICE filename?
JZ ADD_ZERO ;If yes, ASCIIZ.
CMP AH,"I" ;Else, is it INSTALL filename?
JNZ REPLACE_END ;If no, done
ADD_ZERO: XOR AL,AL ;Else, add ASCIIZ.
STOSB
REPLACE_END: RET
REPLACE ENDP
;------------------------------------------;
; Display the commands on the screen. ;
; All registers destroyed. ;
;------------------------------------------;
DISPLAY_IT PROC NEAR
MOV BP,OFFSET DATA_STORAGE ;Point to data storage.
MOV DH,ROW_START ;Point to first display row.
NEXT_DISPLAY: XOR DL,DL ;Column zero.
CALL SET_CURSOR ;Set cursor position.
CMP COMMAND[BP],LAST_RECORD ;Is it the last record?
JZ DISPLAY_END ;If yes, done here.
CALL DECODE ;Else, decode the command.
MOV AL,"=" ;Add quotes and a space.
CALL WRITE_TTY
MOV AL,SPACE
CALL WRITE_TTY
MOV SI,BP ;Point to command string.
INC SI
MOV CX,STRING_LENGTH[BP] ;Retrieve the string length.
NEXT_ARGUMENT: LODSB ;Display the command.
CALL WRITE_TTY
LOOP NEXT_ARGUMENT
ADD BP,TYPE DATA_RECORD ;Point to next record.
INC DH ;Next cursor row.
CMP DH,25 ;Is it row 25?
JNZ NEXT_DISPLAY ;If no, continue.
DISPLAY_END: RET
DISPLAY_IT ENDP
;-----------------------------------------;
; INPUT ;
; BP points to command. ;
; ;
; OUTPUT ;
; The command is decoded and displayed. ;
; ;
; AX, CX, SI and DI destroyed. ;
;-----------------------------------------;
DECODE PROC NEAR
MOV SI,OFFSET INACTIVE ;Assume command inactive.
MOV AL,COMMAND[BP] ;Retrieve command.
TEST AL,HIGH_BIT ;Is it marked inactive?
JNZ FOUND_COMMAND ;If yes, assumed right.
MOV DI,OFFSET CODES ;Else, point to codes.
MOV CX,CODES_LENGTH ;Number of codes.
REPNZ SCASB ;Search for match.
MOV SI,OFFSET TABLE_END ;Point to lookup table.
INC CX ;Adjust count.
FIND_COMMAND: SUB SI,COMMAND_SIZE ;Point to appropriate command.
LOOP FIND_COMMAND
FOUND_COMMAND: MOV CX,COMMAND_SIZE ;Command string length.
DISPLAY_CMD: LODSB ;Display it.
CALL WRITE_TTY
LOOP DISPLAY_CMD
RET
DECODE ENDP
;----------------------------------;
; OUTPUT ;
; Carry flag = 0 if good edit. ;
; Carry flag = 1 if edit abort. ;
; ;
; All registers destroyed. ;
;----------------------------------;
EDIT PROC NEAR
MOV BP,OFFSET DATA_STORAGE ;Point to data storage.
MOV DH,ROW_START ;Point to first row.
MOV BL,INVERSE ;Highlight the first command.
CALL HIGHLIGHT_BAR ;Return with DI = 1; first char.
NEXT_KEY: CALL GET_KEY ;Get a keystroke.
CMP AH,ESC_KEY ;Is it ESC?
JZ NO_CHANGE ;If yes, exit with no change.
CMP AH,F2_KEY ;Is it F2?
JZ EDIT_END ;If yes, exit with changes.
CMP AL,BS ;Is it backspace?
JZ FUNCTION ;If yes, function.
CMP AL,CR ;Is it carriage return?
JZ FUNCTION ;If yes, function.
CMP AH,F1_KEY ;Is it F1 or above?
JAE FUNCTION ;If yes, function.
ASCII: CMP AL,SPACE ;Is it space or above?
JB NEXT_KEY ;If no, skip.
CMP DI,STRING_LENGTH[BP] ;Else, are we at end of field?
JA NEXT_KEY ;If yes, skip.
MOV COMMAND[BP+DI],AL ;Else, store character.
INC DI ;Point to next storage.
INC DL ;Increment cursor column.
CALL WRITE_TTY ;Write the character to screen.
JMP SHORT NEXT_KEY ;Get next keystroke.
FUNCTION: MOV AL,AH ;Scan code in AL.
MOV CX,KEY_COUNT ;Count of active functions.
PUSH DI ;Preserve DI.
MOV DI,OFFSET DISPATCH_KEY ;Point to active keys.
REPNZ SCASB ;Scan for match.
POP DI ;Retrieve DI.
JNZ NEXT_KEY ;If no match, next key.
MOV SI,OFFSET DISPATCH_END ;Else, point to dispatch table.
SHL CX,1 ;Convert to word offset.
SUB SI,CX ;Point to appropriate procedure
CALL DS:[SI] ; and go do it.
JMP SHORT NEXT_KEY ;Get next keystroke.
NO_CHANGE: STC
EDIT_END: RET
EDIT ENDP
;----------------------------------------------------------------------------;
; The following are the active function, arrow and backspace key procedures. ;
;----------------------------------------------------------------------------;
F1 PROC NEAR
PUSH DI ;Preserve DI and DX.
PUSH DX
XOR DL,DL ;Column zero.
CALL SET_CURSOR ;Set cursor.
XOR COMMAND[BP],HIGH_BIT ;Toggle active state.
CALL DECODE ;Decode the command.
POP DX ;Restore cursor position.
CALL SET_CURSOR
POP DI ;Restore DI.
RET
F1 ENDP
;------------------------------;
BACKSPACE PROC NEAR
CMP DI,1 ;Are we already at first char?
JZ BACKSPACE_END ;If yes, skip.
DEC DL ;Else, decrement cursor
DEC DI ; and character storage position.
MOV COMMAND[BP+DI],SPACE ;Store a space.
MOV AL,BS ;Write a backspace, space and
CALL WRITE_TTY ;backspace to screen.
MOV AL,SPACE
CALL WRITE_TTY
MOV AL,BS
CALL WRITE_TTY
BACKSPACE_END: RET
BACKSPACE ENDP
;------------------------------;
UP_ARROW PROC NEAR
CMP BP,OFFSET DATA_STORAGE ;Are we already at top row?
JZ UP_ARROW_END ;If yes, skip.
MOV BL,NORMAL ;Else, return to normal
CALL HIGHLIGHT_BAR ; attribute current row.
SUB BP,TYPE DATA_RECORD ;Move up a record.
DEC DH ;Move cursor up one.
MOV BL,INVERSE ;Display line in inverse video.
CALL HIGHLIGHT_BAR
UP_ARROW_END: RET
UP_ARROW ENDP
;------------------------------;
DN_ARROW PROC NEAR
CMP COMMAND[BP+TYPE DATA_RECORD],LAST_RECORD
JZ DN_ARROW_END
CMP DH,24 ;If last record already or
JZ DN_ARROW_END ; bottom of screen, skip.
MOV BL,NORMAL ;Else, return current row to
CALL HIGHLIGHT_BAR ; normal.
ADD BP,TYPE DATA_RECORD ;Go down a record.
INC DH ;And down a row.
MOV BL,INVERSE ;Display the line inverse video.
CALL HIGHLIGHT_BAR
DN_ARROW_END: RET
DN_ARROW ENDP
;------------------------------;
LT_ARROW PROC NEAR
CMP DI,1 ;Are we already first positon?
JZ LT_ARROW_END ;If yes, skip.
DEC DI ;Else, decrement storage position
DEC DL ; and cursor position.
CALL SET_CURSOR
LT_ARROW_END: RET
LT_ARROW ENDP
;------------------------------;
RT_ARROW PROC NEAR
CMP DI,STRING_LENGTH[BP] ;Are we already end of string?
JA RT_ARROW_END ;If yes, skip.
INC DI ;Else, increment storage position
INC DL ; and cursor position.
CALL SET_CURSOR
RT_ARROW_END: RET
RT_ARROW ENDP
;------------------------------;
HOME PROC NEAR
MOV DI,1 ;Home storage position
MOV DL,COL_START ; and cursor.
CALL SET_CURSOR
RET
HOME ENDP
;------------------------------;
END_CURSOR PROC NEAR
MOV DI,STRING_LENGTH[BP] ;Retrieve string length.
MOV CX,DI
MOV DL,CL
ADD DL,COL_START ;Add to starting column.
INC DI ;Adjust.
CALL SET_CURSOR ;Set cursor.
RET
END_CURSOR ENDP
;------------------------------;
PG_DN PROC NEAR
MOV BL,NORMAL ;Current postion back to normal.
CALL HIGHLIGHT_BAR
NEXT_PG_DN: CMP COMMAND[BP+TYPE DATA_RECORD],LAST_RECORD
JZ PAGE_END
ADD BP,TYPE DATA_RECORD ;If not already last position,
INC DH ; go to it.
JMP SHORT NEXT_PG_DN
PAGE_END: MOV BL,INVERSE ;And display it in inverse video.
CALL HIGHLIGHT_BAR
RET
PG_DN ENDP
;------------------------------;
PG_UP PROC NEAR
MOV BL,NORMAL ;Restore current position to
CALL HIGHLIGHT_BAR ; normal.
MOV BP,OFFSET DATA_STORAGE ;Move to top command.
MOV DH,ROW_START ;And cursor position.
MOV BL,INVERSE ;And highlight.
CALL HIGHLIGHT_BAR
RET
PG_UP ENDP
;------------------------------------------;
; INPUT ;
; BL = attribute. ;
; BP points to current command. ;
; ;
; OUTPUT ;
; DI = 1 (First storage position.) ;
; DL = cursor column start. ;
; ;
; CX, SI destroyed. ;
;------------------------------------------;
HIGHLIGHT_BAR PROC NEAR
MOV CX,STRING_LENGTH[BP] ;Retrieve string length.
MOV SI,BP ;Point to command.
INC SI ;Adjust.
MOV DL,COL_START ;Point to first position.
HIGHLIGHT: CALL SET_CURSOR ;Set the cursor.
LODSB
PUSH CX ;Preserve CX.
MOV CX,1
MOV AH,9 ;Write char/attribute.
INT 10H
INC DL ;Increment cursor postion.
POP CX
LOOP HIGHLIGHT
MOV DL,COL_START ;Point to first position again.
CALL SET_CURSOR ;Set cursor.
MOV DI,1 ;Return with DI = first storage.
RET
HIGHLIGHT_BAR ENDP
;---------------------------------------;
; The following are support procedures. ;
;---------------------------------------;
WRITE_TTY PROC NEAR
MOV AH,0EH ;Write TTY via BIOS.
INT 10H
RET
WRITE_TTY ENDP
;------------------------------;
SET_CURSOR PROC NEAR
XOR BH,BH ;Enter with DX = cursor postion.
MOV AH,2 ;Set cursor position via BIOS.
INT 10H
RET
SET_CURSOR ENDP
;------------------------------;
CLS PROC NEAR
MOV AH,0FH ;Get current video mode.
INT 10H
XOR AH,AH ;Set current video mode.
INT 10H ;Result is a clear screen.
RET
CLS ENDP
;------------------------------;
DELAY PROC NEAR
PUSH DS ;Preserve data segment.
MOV AX,40H ;Point to BIOS data segment.
MOV DS,AX
MOV AX,DS:[6CH] ;Retrieve timer low.
ADD AX,18 ;Add 18 counts per second.
NEXT_COUNT: MOV DX,DS:[6CH] ;Retrieve timer low.
CMP DX,AX ;Have we timed out?
JNZ NEXT_COUNT ;If not, wait until second up.
POP DS ;Restore data segment.
RET
DELAY ENDP
;------------------------------;
GET_KEY: MOV AH,0 ;Retrieve keystroke via BIOS.
INT 16H
RET
CK_KEY: MOV AH,1 ;Check for keystroke via BIOS.
INT 16H
RET
;------------------------------;
PRINT_STRING: MOV AH,9 ;Print string via DOS.
INT 21H
RET
;------------------------------;
DATA_STORAGE EQU $
_TEXT ENDS
END